iT邦幫忙

2023 iThome 鐵人賽

DAY 27
0
Modern Web

30天前端學習筆記心得系列 第 29

Day27-Javascript函數

  • 分享至 

  • xImage
  •  

函數(Function)

一種包裝程式,可以重複使用,會輸入的值執行某些處理程序後,再將結果回傳機制

  • 函數宣告(Function declaration)

function 函數名稱(參數列表) {
  // 函數體
  return 回傳值;
}

function sum(a, b) {
  return a + b;
}
  • 呼叫函數(Calling function)

var result = sum(2, 3);
console.log(result); // 5

return 來回傳值和函數

function createAdder(a) {
  return function(b) {
    return a + b;
  };
}

var adder = createAdder(2);
console.log(adder(3)); // 5
  • 常用用法

    • 程式碼封裝一個單元,可以重複使用
    • 程式碼分解更小模塊,提高程式可讀性和可維護性
    • 程式邏輯分離,提高程式可測試性

原始函數(Primitive Function)

直接在程式碼定義函數
物件函數(object function) 最大區別
原始函數沒有自己原型鏈,無法透過 prototype 屬性存取或繼承物件屬性和方法

  • 使用語法

function myFunction() {
  // 函數體
}

function add(x, y) {
  return x + y;
}
console.log(add(2, 3)); // 5

可以像物件函數使用,透過 call()apply() 傳遞參數和設定作用域

function foo(x) {
  console.log(x);
}

foo.call(null, "bar"); // bar
foo.apply(null, ["bar"]); // bar

可以透過 bind() 綁定到特定物件

function foo() {
  console.log(this.name);
}

var bar = {
  name: "bar"
};

var boundFoo = foo.bind(bar);
boundFoo(); // bar

原始函數不可變的,無法修改原始定義
如果要修改原始函數行為
可以使用 Function.prototype.bind() Function.prototype.defineProperty()

function foo(x) {
  console.log(x);
}

var boundFoo = foo.bind(null, 20);
boundFoo(); // 20


function foo(x) {
  console.log(x);
}

Object.defineProperty(foo, "name", {
  value: "bar"
});

foo(); // bar

箭頭函數(Arrow Function)

新函數表達式,在ES6語法比傳統函數更簡潔、更易讀,適當情況下使用箭頭函數可以提高程式的可讀性和可維護性,具有一些特殊行為

  • 使用語法

// 簡寫體
const foo = (x) => x * 2;

// 塊體
const bar = (x) => {
  return x * 2;
};

箭頭函數簡寫體只有一個運算式,會自動返回運算式結果
塊體可以包含多個語句,需要使用 return 語句來返回結果

  • 箭頭函數與傳統函數區別

    • 箭頭函數沒有 this 關鍵字,因此 this箭頭函數始終指向函數定義位置
    • 箭頭函數沒有 arguments 物件,因此無法直接存取函數所有參數
    • 箭頭函數不能用作構造函數
  • 箭頭函數可以使用情況

    • 匿名函數
    • 回呼函數
    • 方法
// 匿名函數
const add = (x, y) => x + y;

console.log(add(1, 2)); // 3

// 回呼函數
const button = document.querySelector("button");
button.addEventListener("click", () => {
  console.log("clicked");
});

// 方法
class Person {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    return () => console.log("Hello " + this.name);
  }
}

const person = new Person("Cindy");
const hello = person.sayHello();
hello(); // Hello Cindy

匿名函數(Anonymous Function)

指沒有名稱的函數

  • 使用語法

// 簡寫體
const foo = (x, y) => x + y;

// 塊體
const bar = (x, y) => {
  return x + y;
};

匿名函數簡寫體只有一個運算式,會自動返回運算式結果
塊體可以包含多個語句,需要使用 return 語句返回結果

  • 匿名函數使用與定義

    • 回呼函數是指在某個事件發生時被調用函數
    • 匿名函數可以用來實現回呼函數

使用匿名函數處理 click 事件
按鈕被點擊時,匿名函數會被調用,在控制台輸出 clicked
匿名函數也可以用來實現方法

const button = document.querySelector("button");
button.addEventListener("click", () => {
  console.log("clicked");
});

使用匿名函數來實現 Person 物件的 sayHello()
sayHello() 返回一個匿名函數,在控制台輸出Hello Cindy Huang

class Person {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    return () => console.log("Hello " + this.name);
  }
}

const person = new Person("Cindy Huang");
const hello = person.sayHello();
hello(); // Hello Cindy Huang

匿名函數可以用來實現閉包

makeAdder() 返回一個匿名函數,訪問x變量的值
add5變數,將x變量的值設置為7
因此 add5() 函數會返回 7y 變量的和 //27

const makeAdder = (x) => (y) => x + y;

const add5 = makeAdder(5);
console.log(add5(20)); // 27
  • 匿名函數優缺點

    • 定義方式比傳統函數簡潔
    • 可以用在各種情況
    • 沒有名稱,調試時可能會比較困難
    • 行為可能會比較難理解

需要 根據具體情況 選擇是否使用 匿名函數
需要 簡潔靈活性,可以使用 匿名函數
需要 可讀性可維護性,可以使用 傳統函數

閉包(Closure)

一種函數被宣告時在 作用域環境(lexical environment) 的組合

function foo() {
  // 作用域環境
  const x = 20;
  return (y) => x + y;
}

// 閉包
const bar = foo();

// 調用閉包
console.log(bar(10)); // 30
  • 閉包各種功能

    • 私有變量
    • 回調函數
    • 延遲求值
function foo() {
  // 私有變量
  const x = 10;
  return () => x;
}

const bar = foo();
console.log(bar()); // 10

// 嘗試外部訪問 x 變量
console.log(x); // x is not defined

function foo(callback) {
  // 回調函數
  callback();
}

foo(() => console.log("Hello world")); // Hello world

function foo() {
  // 延遲求值
  return new Promise((resolve) => {
    const x = Math.random();
    setTimeout(() => resolve(x), 1000);
  });
}

const bar = foo();
console.log(bar); // Promise {<pending>}

// 獲取結果
bar.then((x) => console.log(x)); // 隨機數
  • 注意事項

    • 記憶體洩漏:閉包引用不再使用變量,變量將不會被釋放,因此導致記憶體洩漏
    • 難理解程式碼:閉包行為可能比較難理解,在使用閉包時需要注意程式的可讀

資料來源:JavaScript Function (函數)
Function 函式
閉包,原來這就是閉包啊!


上一篇
Day26-Javascript陣列物件
下一篇
Day28-JavaScript DOM(尋找元素、節點物件屬性)
系列文
30天前端學習筆記心得34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言